import { Base64 } from 'js-base64';
import { restGet, restPost } from "./rest_lib";
import cosmos_sig from "./cosmos_sig";
let { createAccessToken } = cosmos_sig;

import { signAndBroadcast } from "./blockchain"
const bs58 = require("bs58")

const queryRoot = "/dbchain";

///////////////////////
//                   //
// dbchain queries //
//                   //
///////////////////////

async function checkChainId(chainId) {
  var uri = uriBuilder("check_chain_id", chainId);
  var response = await restGet(uri);
  return response.data.result;
}



async function canInsertRow(appCode, tableName, record) {
  var recordJson = Buffer.from(JSON.stringify(record));
  var recordJsonBase58 = bs58.encode(recordJson);
  var uri = uriBuilder("can_insert_row", appCode, tableName, recordJsonBase58);
  var response = await restGet(uri);
  if (response.data.result == null) {
    return [];
  } else {
    return response.data.result;
  }
}

async function querier(appCode, querierObj) {
  var query = Buffer.from(JSON.stringify(querierObj));
  query = bs58.encode(query);
  var uri = uriBuilder("querier", appCode, query);
  var response = await restGet(uri);
  return response.data.result;
}

//////////////////////////////////
//                              //
// other than dbchain queries   //
//                              //
//////////////////////////////////

async function getAccount(address) {
  if (address == null) {
    return null;
  }
  var response = await restGet(`/auth/accounts/${address}`);
  var account;
  try {
    account = response.data.result.value;
  } catch (e) {
    return null;
  }

  if (account.address == "") {
    return null;
  }
  return account;
}

//////////////////
//              //
// transactions //
//              //
//////////////////



async function insertRow(appCode, tableName, fields, callback) {
  var encodedFields = Base64.encode(JSON.stringify(fields))
  await signAndBroadcast(
    "MsgInsertRow",
    {
      app_code: appCode,
      table_name: tableName,
      fields: encodedFields
    },
    callback
  );
}

async function uploadFile(file, appCode) {
  var uri = uriBuilder("upload", appCode);
  var formData = new FormData();
  formData.append('file', file);
  var response = await restPost(
    uri,
    formData,
    {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    }
  );
  return (response.data.result)
}

async function commit(callback) {
  await signAndBroadcast(
    null,
    null,
    callback
  );
}
//////////////////////
//                  //
// helper functions //
//                  //
//////////////////////

function uriBuilder(...args) {
  if (args.length < 1) {
    throw "At least one parameter is needed!";
  }
  var accessToken = createAccessToken();
  args.splice(1, 0, accessToken);
  args.unshift(queryRoot);
  return args.join("/");
}

/**
 * Executes the current library to specify a custom function
 * @param {String} appCode Your appCode
 * @param {String} FunctionName Custom function name
 * @param {Array} Argument ask sb to do sth ;
 * @param {Function} callback The callback function that fires after execution
 */
async function callFunction(appCode, FunctionName, Argument = [], callback) {
  let data = JSON.stringify(Argument)

  await signAndBroadcast(
    'MsgCallFunction',
    {
      appCode,
      function_name: FunctionName,
      argument: data
    },
    callback
  );
}

/**
 * Executes the current library to specify a custom function
 * @param {String} appCode Your appCode
 * @param {String} FunctionName Custom function name
 * @param {Array} Argument ask sb to do sth ;
 * @param {Function} callback The callback function that fires after execution
 */
async function callCustomQuerier(appCode, FunctionName, Argument = [], callback) {
  let query = '';
  Argument[1].forEach(element => {
    query += bs58.encode(Buffer.from(element)) + '/'
  });
  let bs = query.substring(0, query.length - 1);
  let bss = bs58.encode(Buffer.from(bs))
  var uri = uriBuilder("call-custom-querier", appCode, FunctionName, bss)
  var response = await restGet(uri);
  return response.data.result;
}

export {
  checkChainId, uriBuilder, insertRow, canInsertRow, uploadFile, commit, querier, callFunction, callCustomQuerier, getAccount
};
